package com.scheduled.demo.scheduled;


import com.google.common.base.Stopwatch;
import com.scheduled.demo.config.ApplicationContextHolder;
import com.scheduled.demo.service.RedisDistributedLock;
import com.scheduled.demo.util.DateUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.support.ScheduledMethodRunnable;

import java.lang.reflect.Method;
import java.net.InetAddress;
import java.util.Map;

/**
 * @description:
 * @author: chenjianshuo
 * @create: 2019-08-26 14:39
 **/

public class RedisScheduledMethodRunnable extends ScheduledMethodRunnable {


    private RedisDistributedLock redisDistributedLock;

    private String name;

    private Map<String, Object> map ;

    private Logger logger = LoggerFactory.getLogger(RedisScheduledMethodRunnable.class);

    private final static String  lockKey = "redisLockKey";

    private String methodName;




    public RedisScheduledMethodRunnable(Object target, Method method, RedisDistributedLock redisDistributedLock, Map<String, Object> map) {
        super(target, method);
        this.redisDistributedLock = redisDistributedLock;
        this.map = map;
        methodName = method.getName();
        name = String.format("ip:%s,method: %s", getIp(),methodName);
    }

    private String getIp() {
        String ip = "";
        try {
            ip = InetAddress.getLocalHost().getHostAddress();
        } catch (Exception e) {

        }
        return ip;
    }

    @Override
    public void run() {
        String dateTime = DateUtil.getCurrDateStr((String) map.get("pattern"));
        String key = getLockKey((String) map.get("lockKey"),dateTime);
        String value = getLockValue((String) map.get("lockValue"),dateTime) ;
        long expire = (long) map.get("expire");
        //如果当前实例取不到锁, 不执行任务
        if (getLock(key,value,expire)) {
            Stopwatch stopwatch = Stopwatch.createStarted();
            logger.info(String.format("定时任务[%s]运行: %s", name,key));
            try {
                //执行任务
                super.run();
            } catch (Throwable e) {
                logger.error(String.format("定时任务[%s]运行的时候发生错误: %s", name, e.getMessage()), e);
                throw e;
            } finally {
                stopwatch.stop();
                redisDistributedLock.releaseLock(key,value);
                logger.info(String.format("定时任务[%s]运行结束, 耗时: %s", name, stopwatch.toString()));
                return;
            }
        }
            logger.info(String.format("定时任务[%s]取不到鎖运行结束", name));

    }

    private boolean getLock(String key, String value, long expire) {
        return redisDistributedLock.setLock(key,value,expire);
    }

    private String getLockKey(String key, String dateMin){
        Environment env = ApplicationContextHolder.context.getBean(Environment.class);
        String appName = env.getProperty("spring.application.name");
        if(StringUtils.isBlank(key)){
            key = methodName;
        }
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(appName).append(":").append(lockKey).append(":").append(key).append(dateMin);
        return stringBuilder.toString();
    }

    private String getLockValue(String value, String dateTime) {
        return value + dateTime;
    }
}

